from scipy.spatial.distance import pdist, squareform
from scipy.linalg import eigh
import numpy as np
from sklearn.datasets import make_moons


def rbf_kpca(X, gamma, k):
    sq_dists = pdist(X, metric='sqeuclidean')
    mat_sq_dists = squareform(sq_dists)
    K = np.exp(-gamma * mat_sq_dists)
    N = X.shape[0]
    one_N = np.ones((N, N)) / N

    K = K - one_N.dot(K) - K.dot(one_N) + one_N.dot(K).dot(one_N)

    Lambda, Q = np.linalg.eigh(K)

    alphas = np.column_stack((Q[:, -i] for i in range(1, 1 + k)))
    lambdas = [Lambda[-i] for i in range(1, k + 1)]

    return alphas, lambdas


def proj_new(X_new, X, alphas, lambdas, gamma=15):
    k = np.exp(-gamma * np.sum((X - X_new) ** 2, 1))
    return k.dot(alphas / lambdas)
    # alphas/lambdas，归一化后的alphas


def test():
    X, y = make_moons(n_samples=100, random_state=123)
    # 设置random_state，为了可重复性
    alphas, lambdas = rbf_kpca(X, gamma=15, k=1)
    X_new = X[25]
    # 以当前样本的某一样本作为新的样本进行测试
    X_proj = proj_new(X_new, X, alphas, lambdas)
    print(alphas[25])
    print(X_proj)
    # [-0.07877284]
    # [-0.07877284]
